from datetime import datetime
import can
import cantools
from can.interfaces.pcan import PcanBus
from PCANBasic import *  ## PCAN-Basic library import
import sys
import PyQt5.QtWidgets as qw
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QTableWidgetItem, QTreeWidgetItem, QTreeWidget, \
    QMainWindow,QMessageBox
import threading
from time import sleep
from PyQt5.QtCore import QThread, pyqtSignal, QTimer, QObject, Qt
from BRP import *
import win32event
from udsoncan.client import Client
import udsoncan
from udsoncan.connections import BaseConnection, PythonIsoTpConnection
import isotp
import udsoncan.configs
from Crypto.Cipher import AES
from Crypto.Hash import CMAC
import hashlib
from binascii import b2a_hex, a2b_hex, unhexlify

TOPBIT = 0x8000
POLYNOM_1 = 0x8408
POLYNOM_2 = 0x8025
BITMASK = 0x0080
# INITIAL_REMINDER = 0xFFFE
MSG_LEN = 2  #seed length in bytes

L61_TOPBIT = 0x8000
L61_POLYNOM_1 = 0x2346
L61_POLYNOM_2 = 0x8752
L61_BITMASK = 0x0080
# L61_INITIAL_REMINDER = 0xFFFE
L61_MSG_LEN = 2

EGSM_TX_ID = 0x7C4
EGSM_RX_ID_PHYS = 0x7CC
EGSM_RX_ID_FUNC = 0x7CC
FLASH_DRIVER_ADDRESS = 0X1FFFE800
APP_ADDRESS = 0X8000
ecuXorArray = [0x47, 0x53, 0x4D, 0x4B]
ecuXorArray60 = [0x4B, 0x4D, 0x53, 0x47]

DiagnosticCode = 0xF100
SoftwareReleaseDate = 0xF101
bootVersion = 0xF180
SoftwareFileName = 0xF181
FingerPrint = 0xF185
ActiveDiagnosticSession = 0xF186
BRPSwNumber = 0xF188
BRPHwNumber = 0xF191
ManufacturerHwNumber = 0xF192
ManufacturerSwNumber = 0xF194
ECUBuildDate = 0xF18B
ECUSerialNo = 0xF18C  #: udsoncan.DidCodec('BBBBBBBBB'),  # ECU Serial No.  9bytes
ActuaterType = 0xCF00  # udsoncan.AsciiCodec(1),  # Actuater type
HallLatchSpeed = 0xF1F0  # udsoncan.DidCodec('BBBB'),  #
HallLatchCalData = 0xF1F1  # udsoncan.AsciiCodec(32),  # Hall Latch Cal Data
AnalogPositionCalData = 0xF1F2  # udsoncan.AsciiCodec(12),  # Analog Position Cal Data
Status = 0xCF01  # udsoncan.DidCodec('B'),  # Status 1Byte
Mode = 0xCF02  # udsoncan.DidCodec('B'),  # Mode 1Byte
AngleSetpoint = 0xCF03  # udsoncan.DidCodec('BB'),  #  2Byte
AnglePosition = 0xCF04  # udsoncan.DidCodec('BB'),  # Angle Position 2Byte
CurrentLinite = 0xCF05  # udsoncan.DidCodec('BB'),  # Current Linite 2Byte
CurrentSetpoint = 0xCF06  # udsoncan.DidCodec('BB'),  # Current setpoint 2Byte
CurrentPhase = 0xCF07  # udsoncan.DidCodec('B'),  # Current phase 1Byte
CurrentSum = 0xCF08  # udsoncan.DidCodec('BB'),  # Current Sum 2Byte
SpeedLimit = 0xCF09  # udsoncan.DidCodec('BB'),  # Speed Limit  2Byte
SpeedSetpoint = 0xCF0A  # udsoncan.DidCodec('BB'),  # Speed setpoint 2Byte
MotorTemperature = 0xCF10  # udsoncan.DidCodec('B'),  #   1Byte
CalibrationIDForCANTx = 0xCF20  # udsoncan.DidCodec('BB'),  # Calibration ID for CAN Tx 2Byte
HardwareIDForCANTx = 0xCF21  # udsoncan.DidCodec('BB'),  # Hardware ID for CAN Tx 2Byte
SoftwareIDForCANTx = 0xCF22  # udsoncan.DidCodec('BB'),  # Software ID for CAN Tx 2Byte
ECUInputVoltatgeContinuous = 0xA801  # udsoncan.DidCodec('B'),  # ECU input voltatge continuous 1Byte
ECUTemperature = 0xA802  # udsoncan.DidCodec('B'),  # ECU temperature 1Byte


class PrpCrypt(object):
    def __init__(self, key):
        # 初始化方法
        if isinstance(key, str):
            self.key = key.encode('utf-8')
        elif isinstance(key, bytes):
            self.key = key

        #self.iv = Random.new().read(AES.block_size)  #CBC模式使用，随机
        self.iv = '1234567812345678'.encode('utf-8')

    def encrypt(self, text):
        # 加密函数，如果text不足16个字节就使用空格来补足16位
        # 16位密钥规则
        # text-需要加密的数据
        # return 统一加密后的字符串转换为16进制字符串

        bs = AES.block_size  ##密钥的长度AES-128(16位)

        # PKCS5填充,填充缺少的位数值，例如加密的数据是4字节，那填充的就是(16-4)=12
        PADDING = lambda s: s + (bs - len(s) % bs) * chr(bs - len(s) % bs)
        mode = AES.MODE_ECB  #使用ECB加密
        cryptor = AES.new(self.key, mode)

        if isinstance(text, str):  # 如果输入的是字符串
            self.ciphertext = cryptor.encrypt(PADDING(text).encode('utf-8'))

        elif isinstance(text, bytes):  # 如果输入的是二进制数
            count = len(text)  # 用户输入的字符串的长度
            if count < bs:
                add = (bs - count)
                for i in range(add):
                    text = text + chr(add).encode('utf-8')  #逐一加上缺少的数值的bytes值
            elif count > bs:
                add = bs - (count % bs)
                for i in range(add):
                    text = text + chr(add).encode('utf-8')
            print("text：", text)
            self.ciphertext = cryptor.encrypt(text)
        else:
            print("Input data is not hashable.")

        print("密钥：", self.ciphertext)
        return self.ciphertext  #b2a_hex(self.ciphertext) #返回16进制数据

    def decrypt(self, code):
        # 解密函数
        mode = AES.MODE_ECB  # 使用ECB加密
        cryptor = AES.new(self.key, mode)
        plain_text = cryptor.decrypt(bytes.fromhex(code))
        for i in range(16):
            pad = chr(i).encode('utf-8')
            if pad in plain_text:
                text = plain_text.rstrip(chr(i).encode('utf-8'))
        return b2a_hex(text)

    def encrypt_CMA(self, secret, message):
        c = CMAC.new(secret, message, ciphermod=AES)  #secret-16位密钥
        code = c.hexdigest()
        print("CMAC code:", code)
        return (code)


###*****************************************************************
### Timer class
###*****************************************************************

class TimerRepeater(object):
    """
    A simple timer implementation that repeats itself
    """

    # Constructor
    #
    def __init__(self, name, interval, target, isUi, args=[], kwargs={}):
        """
        Creates a timer.

        Parameters:
            name        name of the thread
            interval    interval in second between execution of target
            target      function that is called every 'interval' seconds
            args        non keyword-argument list for target function
            kwargs      keyword-argument list for target function
        """
        # define thread and stopping thread event
        self._name = name
        self._thread = None
        self._event = None
        self._isUi = isUi
        # initialize target and its arguments
        self._target = target
        self._args = args
        self._kwargs = kwargs
        # initialize timer
        self._interval = interval
        self._bStarted = False

    # Runs the thread that emulates the timer
    #
    def _run(self):
        """
        Runs the thread that emulates the timer.

        Returns:
            None
        """
        while not self._event.wait(self._interval):
            if self._isUi:
                # launch target in the context of the main loop
                pass
                # root.after(1, self._target,*self._args, **self._kwargs)
            else:
                self._target(*self._args, **self._kwargs)

    # Starts the timer
    #
    def start(self):
        """
        Starts the timer

        Returns:
            None
        """
        # avoid multiple start calls
        if (self._thread == None):
            self._event = threading.Event()
            self._thread = threading.Thread(None, self._run, self._name)
            self._thread.start()

    # Stops the timer
    #
    def stop(self):
        """
        Stops the timer

        Returns:
            None
        """
        if (self._thread != None):
            self._event.set()
            self._thread = None


# 自定义信号
class ShiftSignal(QObject):
    park = pyqtSignal(int)
    reverse = pyqtSignal(int)
    neutral = pyqtSignal(int)
    high = pyqtSignal(int)
    low = pyqtSignal(int)


# # 实例化自定义信号
UI_SIGNAL = ShiftSignal()


# 自定义委托类，用于实现自动换行

# 打开CAN总线
def openPCAN():
    can0 = can.interface.Bus(interface='pcan', channel='PCAN_USBBUS1', bitrate=500000)
    return can0

class myMainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.canbus = None
        self.setupUi(self)
        self.DeviceInit()
        self.REFRESH_VALUE = 0
        self.bus = None
        self.receive_thread = None
        self.data_dict = {}  # 用于存储按 CAN ID 分类的数据
        self.db = None  # 初始化 DBC 数据库为 None
        self.start_receiving_flag = False
        # self.myTimer()
        # 绑定信号与槽
        self.actionPcanConnect.triggered.connect(self.actionChannel01_cb)  # 连接通道1
        self.pushButton.clicked.connect(lambda: self.ReadDid(DiagnosticCode))  # DiagnosticCode
        self.pushButton_3.clicked.connect(lambda: self.ReadDid(bootVersion))
        self.pushButton_2.clicked.connect(lambda: self.ReadDid(SoftwareReleaseDate))
        self.pushButton_4.clicked.connect(lambda: self.ReadDid(SoftwareFileName))
        self.pushButton_5.clicked.connect(lambda: self.ReadDid(FingerPrint))
        self.pushButton_6.clicked.connect(lambda: self.ReadDid(ActiveDiagnosticSession))
        self.pushButton_7.clicked.connect(lambda: self.ReadDid(BRPSwNumber))
        self.pushButton_8.clicked.connect(lambda: self.ReadDid(BRPHwNumber))
        self.pushButton_9.clicked.connect(lambda: self.ReadDid(ManufacturerHwNumber))
        self.pushButton_10.clicked.connect(lambda: self.ReadDid(ManufacturerSwNumber))
        self.pushButton_11.clicked.connect(lambda: self.ReadDid(AnalogPositionCalData))
        self.pushButton_12.clicked.connect(lambda: self.ReadDid(ActuaterType))
        self.pushButton_13.clicked.connect(lambda: self.ReadDid(Mode))
        self.pushButton_14.clicked.connect(lambda: self.ReadDid(HallLatchSpeed))
        self.pushButton_15.clicked.connect(lambda: self.ReadDid(Status))
        self.pushButton_16.clicked.connect(lambda: self.ReadDid(ECUBuildDate))
        self.pushButton_17.clicked.connect(lambda: self.ReadDid(AnglePosition))
        self.pushButton_18.clicked.connect(lambda: self.ReadDid(ECUSerialNo))
        self.pushButton_19.clicked.connect(lambda: self.ReadDid(HallLatchCalData))
        self.pushButton_20.clicked.connect(lambda: self.ReadDid(AngleSetpoint))
        self.pushButton_21.clicked.connect(lambda: self.ReadDid(HardwareIDForCANTx))
        self.pushButton_22.clicked.connect(lambda: self.ReadDid(MotorTemperature))
        self.pushButton_23.clicked.connect(lambda: self.ReadDid(CurrentLinite))
        self.pushButton_24.clicked.connect(lambda: self.ReadDid(SpeedLimit))
        self.pushButton_25.clicked.connect(lambda: self.ReadDid(CurrentSetpoint))
        self.pushButton_26.clicked.connect(lambda: self.ReadDid(SpeedSetpoint))
        self.pushButton_27.clicked.connect(lambda: self.ReadDid(CurrentPhase))
        self.pushButton_28.clicked.connect(lambda: self.ReadDid(CurrentSum))
        self.pushButton_29.clicked.connect(lambda: self.ReadDid(SoftwareIDForCANTx))
        self.pushButton_30.clicked.connect(lambda: self.ReadDid(CalibrationIDForCANTx))
        self.pushButton_31.clicked.connect(lambda: self.ReadDid(ECUInputVoltatgeContinuous))
        self.pushButton_32.clicked.connect(lambda: self.ReadDid(ECUTemperature))
        self.pushButton_34.clicked.connect(self.start_receiving)
        self.pushButton_36.clicked.connect(self.stop_receiving)
        self.pushButton_35.clicked.connect(self.add_dbc_file)
        # 创建 TreeWidget 控件
        self.tree_widget = self.treeWidget
        # 设置滚动条策略，确保滚动条始终可用
        self.tree_widget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.tree_widget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        # 设置自定义委托，实现自动换行


        # 界面及参数初始化
    def DeviceInit(self):
        self.m_objPCANBasic = PCANBasic()
        self.m_PcanHandle = PCAN_USBBUS1
        self.m_CanRead = False
        self.m_ReadThread = None
        self.m_Terminated = False
        self._lock = threading.RLock()
        self.m_ReceiveEvent = win32event.CreateEvent(None, 0, 0, None)
        # bManualReset(参数2)：[输入]指定将事件对象创建成手动复原还是自动复原。如果是TRUE，那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态。
        # 如果设置为FALSE，当事件被一个等待线程释放以后，系统将会自动将事件状态复原为无信号状态。
        # bInitialState（参数3）：[输入]指定事件对象的初始状态。如果为TRUE，初始状态为有信号状态；否则为无信号状态。
        self.tmrRead = TimerRepeater("tmrRead", 0.050, self.tmrRead_Tick, False)
        self.isCh1Open = False
        self.isCh1HasMes = False
        self.is_extendMode = False
        self.is_L61 = False

        self.tb_message = self.textEdit
        self.tb_message.setReadOnly(True)
        self.tb_message.setStyleSheet("background-color: rgb(255, 255, 255);")
        self.tb_message.setTextColor(QtGui.QColor(0, 0, 0))

        # emit信号初始化
        self.position_park = 0
        self.position_reverse = 0
        self.position_center = 0
        self.position_high = 0
        self.position_low = 0
        # RadioButton颜色设置

        self.isotp_params = {
            'stmin': 32,
            # Will request the sender to wait 32ms between consecutive frame. 0-127ms or 100-900ns with values from 0xF1-0xF9.流控帧间隔时间，0-127ms 或 100-900ns 值从 0xF1-0xF9
            'blocksize': 8,
            # Request the sender to send 8 consecutives frames before sending a new flow control message.流控帧单包大小，0表示不限制
            'wftmax': 0,  # Number of wait frame allowed before triggering an error
            'tx_data_length': 8,  # Link layer (CAN layer) works with 8 byte payload (CAN 2.0)
            'tx_padding': 0,
            # Will pad all transmitted CAN messages with byte 0x00. None means no padding. 当 notNone表示用于填充发送的消息的字节
            'rx_flowcontrol_timeout': 1000,
            # Triggers a timeout if a flow control is awaited for more than 1000 milliseconds.在停止接收和触发之前等待流控制帧的毫秒数
            'rx_consecutive_frame_timeout': 1000,
            # Triggers a timeout if a consecutive frame is awaited for more than 1000 milliseconds. 在停止接收和触发 a 之前等待连续帧的毫秒数
            # 'squash_stmin_requirement': False
            # When sending, respect the stmin requirement of the receiver. If set to True, go as fast as possible.
        }

    # 刷新界面
    def refreshNeutral(self, int):
        self.rbt_neutral.setChecked(True if int == 1 else False)

    def refreshReverse(self, int):
        self.rbt_reverse.setChecked(True if int == 1 else False)

    def refreshPark(self, int):
        self.rbt_park.setChecked(True if int == 1 else False)

    def refreshLow(self, int):
        self.rbt_low.setChecked(True if int == 1 else False)

    def refreshHigh(self, int):
        self.rbt_high.setChecked(True if int == 1 else False)

    # 每隔300ms更新界面
    def myTimer(self):
        timer = QTimer(self)
        timer.timeout.connect(self.UI_update)
        timer.start(1000)

    def UI_update(self):
        QApplication.processEvents()  # 刷新界面
        print("界面刷新")

    # 连接通道1，链接前，对DID进行配置
    def actionChannel01_cb(self):
        # gets the connection values
        #
        baudrate = PCAN_BAUD_500K
        hwtype = PCAN_USBBUS1
        ioport = 0
        interrupt = 0

        content = self.actionPcanConnect.text()
        print(content)
        try:

            if content == "PcanConnect":
                # Connects a selected PCAN-Basic channel
                #
                # result = self.m_objPCANBasic.Initialize(self.m_PcanHandle, baudrate, hwtype, ioport, interrupt)
                if self.start_receiving_flag == True:
                    self.bus.shutdown()
                self.canbus = openPCAN()

                
                result = self.m_objPCANBasic.GetStatus(PCAN_USBBUS1)
                if result == PCAN_ERROR_OK:
                    #检查CAN网络
                    self.can_message_check()
                    sleep(0.5)
                    #开启协议栈
                    self._isotpaddr_PHYS = isotp.Address(isotp.AddressingMode.Normal_11bits, txid=0x7c4,
                                                         rxid=0x7CC)  # 网络层寻址方法
                    self.tp_stack = isotp.CanStack(bus=self.canbus, address=self._isotpaddr_PHYS,
                                                   params=self.isotp_params)  # 网络/传输层（IsoTP 协议）
                    self.conn = PythonIsoTpConnection(self.tp_stack)  # 应用层和传输层之间建立连接

                    self.config = dict(udsoncan.configs.default_client_config)
                    self.config['security_algo'] = self.SecAlgo
                    self.config['security_algo_params'] = dict(INITIAL_REMINDER=0xFFFE)
                    self.config['data_identifiers'] = {
                        # Codec that read ASCII string. We must tell the length of the string
                        0xF100: udsoncan.DidCodec('BBBB'),  # DiagnosticCode
                        # 0xF100:udsoncan.DidCodec('BBBB'),
                        0xF101: udsoncan.DidCodec('BBB'),  # SoftwareReleaseDate
                        0xF180: udsoncan.AsciiCodec(32),  # boot version
                        0xF181: udsoncan.AsciiCodec(21),  # Software File Name
                        0xF185: udsoncan.DidCodec('BBBBBB'),  # FingerPrint
                        0xF186: udsoncan.DidCodec('B'),  #当前有效诊断会话
                        0xF188: udsoncan.AsciiCodec(18),  # BRP SW Number.
                        0xF191: udsoncan.AsciiCodec(18),  # BRP HW Number
                        0xF192: udsoncan.AsciiCodec(10),  # Manufacturer HW Number
                        0xF194: udsoncan.AsciiCodec(40),  # Manufacturer SW Number
                        0xF18B: udsoncan.DidCodec('BBB'),  # ECU build date
                        0xF18C: udsoncan.AsciiCodec(9),  # ECU Serial No.  9bytes
                        0xCF00: udsoncan.DidCodec('B'),  # Actuater type
                        0xF1F0: udsoncan.DidCodec('BBBB'),  # Hall Latch Speed
                        0xF1F1: udsoncan.DidCodec('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'),  # Hall Latch Cal Data
                        0xF1F2: udsoncan.DidCodec('BBBBBBBBBBBB'),  # Analog Position Cal Data
                        0xCF01: udsoncan.DidCodec('B'),  # Status 1Byte
                        0xCF02: udsoncan.DidCodec('B'),  # Mode 1Byte
                        0xCF03: udsoncan.DidCodec('BB'),  # Angle setpoint 2Byte
                        0xCF04: udsoncan.DidCodec('BB'),  # Angle Position 2Byte
                        0xCF05: udsoncan.DidCodec('BB'),  # Current Linite 2Byte
                        0xCF06: udsoncan.DidCodec('BB'),  # Current setpoint 2Byte
                        0xCF07: udsoncan.DidCodec('B'),  # Current phase 1Byte
                        0xCF08: udsoncan.DidCodec('BB'),  # Current Sum 2Byte
                        0xCF09: udsoncan.DidCodec('BB'),  # Speed Limit  2Byte
                        0xCF0A: udsoncan.DidCodec('BB'),  # Speed setpoint 2Byte
                        0xCF10: udsoncan.DidCodec('B'),  # Motor temperature  1Byte
                        0xCF20: udsoncan.DidCodec('BB'),  # Calibration ID for CAN Tx 2Byte
                        0xCF21: udsoncan.DidCodec('BB'),  # Hardware ID for CAN Tx 2Byte
                        0xCF22: udsoncan.DidCodec('BB'),  # Software ID for CAN Tx 2Byte
                        0xA801: udsoncan.DidCodec('B'),  # ECU input voltatge continuous 1Byte
                        0xA802: udsoncan.DidCodec('B'),  # ECU temperature 1Byte

                    }
                    self.config['input_output'] = {0x3B90: udsoncan.DidCodec('B'), }
                    self.config['server_address_format'] = 32
                    self.config['server_memorysize_format'] = 32
                    self.config['standard_version'] = 2006
                    # self.config['use_server_timing'] = True
                    self.config['request_timeout'] = 5
                    self.config['dtc_snapshot_did_size'] = 0x01

                    with Client(self.conn, config=self.config, request_timeout=2) as self.udsclient:
                        pass
                        # self.conn.open()  # 打开连接
                        # self.conn.close()

                    # Prepares the PCAN-Basic's PCAN-Trace file
                    self.isCh1Open = True
                    print('Is open的状态是：', self.isCh1Open)
                    print("通道1已连接")
                    self.tb_message.setText("提示：通道1已连接！")
                    self.tb_message.ensureCursorVisible()
                    self.tb_message.moveCursor(self.tb_message.textCursor().End)

                    if self.isCh1HasMes == True:
                        self.tb_message.ensureCursorVisible()
                        self.tb_message.append("提示：CAN通讯已连接！")
                        self.tb_message.moveCursor(self.tb_message.textCursor().End)
                        self.IO_ON.setEnabled(True)
                        self.IO_OFF.setEnabled(True)
                    else:
                        self.tb_message.ensureCursorVisible()
                        self.tb_message.append("提示：电子换挡器不在线，请确保通讯正常！")
                        self.tb_message.moveCursor(self.tb_message.textCursor().End)
                else:
                    print("CAN Initial Error!")

            else:
                # Releases a current connected PCAN-Basic channel

                result = self.m_objPCANBasic.Uninitialize(PCAN_USBBUS1)

                if result != PCAN_ERROR_OK:
                    # An error occurred, get a text describing the error and show it
                    #
                    print("Error!", self.GetFormatedError(result))
                else:
                    self.isCh1Open = False
                    print("通道1已释放")
                    self.tb_message.ensureCursorVisible()
                    self.tb_message.setText("提示：通道1已释放！")


        except Exception as err:
            print('出现问题')
            print(err)

    #确认是否有通讯
    def can_message_check(self):
        i = 0
        while (i < 100):
            CANMsg = TPCANMsg()
            CANMsg.ID = 0x7C4
            CANMsg.MSGTYPE = PCAN_MESSAGE_STANDARD
            CANMsg.LEN = 8
            CANMsg.DATA[0] = 0x02
            CANMsg.DATA[1] = 0x10
            CANMsg.DATA[2] = 0x01
            CANMsg.DATA[3] = 0x00
            CANMsg.DATA[4] = 0x00
            CANMsg.DATA[5] = 0x00
            CANMsg.DATA[6] = 0x00
            CANMsg.DATA[7] = 0x00
            self.WriteFrame(CANMsg)

            result = self.m_objPCANBasic.Read(self.m_PcanHandle)
            print("result[0]:", result[0])
            if result[0] == PCAN_ERROR_QRCVEMPTY:
                self.isCh1HasMes = False
                i += 1
                sleep(0.04)
                if i >= 100:
                    print("无CAN通讯，请确保通讯正常")
            else:
                self.isCh1HasMes = True
                print("CAN通讯已连接")
                break

    # -------------------------------------------------------------------------------------------------- #
    ## Thread-Function used for reading PCAN-Basic messages
    ## 数据接收线程
    def CANReadThreadFunc(self):
        try:
            self.m_Terminated = False

            # Configures the Receive-Event.
            stsResult = self.m_objPCANBasic.SetValue(self.m_PcanHandle, PCAN_RECEIVE_EVENT, self.m_ReceiveEvent)
            if stsResult != PCAN_ERROR_OK:
                print("Error: " + self.GetFormatedError(stsResult))
            else:
                while not self.m_Terminated:
                    if win32event.WaitForSingleObject(self.m_ReceiveEvent, 50) == win32event.WAIT_OBJECT_0:
                        print("开始读数据")
                        self.ReadMessages()

                # Resets the Event-handle configuration
                self.m_objPCANBasic.SetValue(self.m_PcanHandle, PCAN_RECEIVE_EVENT, 0)
        except:
            print("Error occurred while processing CAN data")

    ## Thread-Function used for reading PCAN-Basic messages
    ## 数据发送线程
    def CANSendThreadFunc(self):
        try:
            # self.m_Terminated = False
            while not self.m_Terminated:
                # if self.cb_pos_act.isChecked():
                print("开始发送数据")

                lightIndex = self.comboBox_light.currentIndex()
                lightText = self.comboBox_light.itemText(lightIndex)
                print("lightText:{}".format(lightText))
                if self.radioButton_FV.isChecked():
                    CANMsgGBC = TPCANMsg()
                    CANMsgGBC.ID = 0x129
                    CANMsgGBC.MSGTYPE = PCAN_MESSAGE_STANDARD
                    CANMsgGBC.LEN = 8
                    if lightText == "Init":
                        CANMsgGBC.DATA[0] = 0x08
                    elif lightText == "Park":
                        CANMsgGBC.DATA[0] = 0x09
                    elif lightText == "Reverse":
                        CANMsgGBC.DATA[0] = 0x0A
                    elif lightText == "Neutral":
                        CANMsgGBC.DATA[0] = 0x0B
                    elif lightText == "Low":
                        CANMsgGBC.DATA[0] = 0x0C
                    elif lightText == "High":
                        CANMsgGBC.DATA[0] = 0x0D
                    elif lightText == "Moto_running/Reserved":
                        CANMsgGBC.DATA[0] = 0x0E
                    CANMsgGBC.DATA[1] = 0x00
                    CANMsgGBC.DATA[2] = 0x00
                    CANMsgGBC.DATA[3] = 0x00
                    CANMsgGBC.DATA[4] = 0x00
                    CANMsgGBC.DATA[5] = 0x00
                    CANMsgGBC.DATA[6] = 0x00
                    CANMsgGBC.DATA[7] = 0x00
                    self.WriteFrame(CANMsgGBC)
                    sleep(0.02)

                if self.radioButton_EV.isChecked():
                    CANMsgBCM = TPCANMsg()
                    CANMsgBCM.ID = 0x10D
                    CANMsgBCM.MSGTYPE = PCAN_MESSAGE_STANDARD
                    CANMsgBCM.LEN = 8
                    if lightText == "Init":
                        CANMsgBCM.DATA[0] = 0x02
                    elif lightText == "Park":
                        CANMsgBCM.DATA[0] = 0x06
                    elif lightText == "Reverse":
                        CANMsgBCM.DATA[0] = 0x0A
                    elif lightText == "Neutral":
                        CANMsgBCM.DATA[0] = 0x0E
                    elif lightText == "Low":
                        CANMsgBCM.DATA[0] = 0x12
                    elif lightText == "High":
                        CANMsgBCM.DATA[0] = 0x16
                    elif lightText == "Moto_running/Reserved":
                        CANMsgBCM.DATA[0] = 0x1A
                    CANMsgBCM.DATA[1] = 0x80
                    CANMsgBCM.DATA[2] = 0x00
                    CANMsgBCM.DATA[3] = 0x00
                    CANMsgBCM.DATA[4] = 0x00
                    CANMsgBCM.DATA[5] = 0x00
                    CANMsgBCM.DATA[6] = 0x00
                    CANMsgBCM.DATA[7] = 0x00
                    self.WriteFrame(CANMsgBCM)
                    sleep(0.02)
                    print("send BCM info!")

                CANMsgBKLight = TPCANMsg()
                CANMsgBKLight.ID = 0x207
                CANMsgBKLight.MSGTYPE = PCAN_MESSAGE_STANDARD
                CANMsgBKLight.LEN = 8
                if self.radioButton_BKON.isChecked():
                    CANMsgBKLight.DATA[0] = 0x40
                elif self.radioButton_BKOFF.isChecked():
                    CANMsgBKLight.DATA[0] = 0x00
                CANMsgBKLight.DATA[1] = 0x00
                CANMsgBKLight.DATA[2] = 0x00
                CANMsgBKLight.DATA[3] = 0x00
                CANMsgBKLight.DATA[4] = 0x00
                CANMsgBKLight.DATA[5] = 0x00
                CANMsgBKLight.DATA[6] = 0x00
                CANMsgBKLight.DATA[7] = 0x00
                self.WriteFrame(CANMsgBKLight)
                sleep(0.02)
        except:
            print("Error occurred while sending CAN data")

    ## Help Function used to get an error as text
    ## 故障检测
    def GetFormatedError(self, error):
        # Gets the text using the GetErrorText API function
        # If the function success, the translated error is returned. If it fails,
        # a text describing the current error is returned.
        #
        stsReturn = self.m_objPCANBasic.GetErrorText(error, 0)
        if stsReturn[0] != PCAN_ERROR_OK:
            return "An error occurred. Error-code's text ({0:X}h) couldn't be retrieved".format(error)
        else:
            return stsReturn[1]

    def tmrRead_Tick(self):
        # Checks if in the receive-queue are currently messages for read
        #
        self.ReadMessages()

    ## Function for reading CAN messages on normal CAN devices
    ## 读报文
    def ReadMessages(self):
        stsResult = PCAN_ERROR_OK

        # We read at least one time the queue looking for messages.
        # If a message is found, we look again trying to find more.
        # If the queue is empty or an error occurr, we get out from
        # the dowhile statement.
        #
        while (self.m_CanRead and not (stsResult & PCAN_ERROR_QRCVEMPTY)):

            stsResult = self.ReadMessage()

            if stsResult == PCAN_ERROR_ILLOPERATION:
                break

    def ReadMessage(self):
        # We execute the "Read" function of the PCANBasic
        #
        result = self.m_objPCANBasic.Read(self.m_PcanHandle)
        print("result[0]:", result[0])

        if result[0] == PCAN_ERROR_OK:
            # We show the received message
            #
            revMsg = self.ProcessMessage(result[1:])
            # 如果挡位接收使能打开，则判断挡位
            # if self.cb_pos_act.isChecked():
            self.LeverPosition(revMsg)

        return result[0]

    ## Processes a received message, in order to show it in the Message-ListView
    ## 报文处理
    def ProcessMessage(self, *args):
        with self._lock:
            canMsg = []
            # Split the arguments. [0] TPCANMsg, [1] TPCANTimestamp
            #
            theMsg = args[0][0]
            itsTimeStamp = args[0][1]

            newMsg = TPCANMsg()
            newMsg.ID = theMsg.ID
            newMsg.DLC = theMsg.LEN
            canMsg.append(hex(newMsg.ID))
            for i in range(8):
                newMsg.DATA[i] = theMsg.DATA[i]
                canMsg.append(''.join(hex(theMsg.DATA[i])).replace("0x", '').zfill(2))
            newMsg.MSGTYPE = theMsg.MSGTYPE
            print(canMsg)

            newTimestamp = TPCANTimestamp()
            newTimestamp.value = (
                    itsTimeStamp.micros + 1000 * itsTimeStamp.millis + 0x100000000 * 1000 * itsTimeStamp.millis_overflow)
            return newMsg


    # 发送报文
    def WriteFrame(self, msg):
        CANMsg = msg

        # The message is sent to the configured hardware
        result = self.m_objPCANBasic.Write(self.m_PcanHandle, CANMsg)
        if result != PCAN_ERROR_OK:
            # An error occurred, get a text describing the error and show it
            #
            ret = self.m_objPCANBasic.GetErrorText(result)
            print(ret[1])
        else:
            print("Message sent successfully")
            return result

    # 读取一帧报文
    def ReadSingleMsg(self):
        try:
            # self.CANMsgFilter()
            result = self.m_objPCANBasic.Read(self.m_PcanHandle)
            if result[0] == PCAN_ERROR_OK:
                # We show the received message
                canMsg = []
                # Split the arguments. [0] TPCANMsg, [1] TPCANTimestamp
                theMsg = result[1]

                newMsg = TPCANMsg()
                newMsg.ID = theMsg.ID
                newMsg.DLC = theMsg.LEN
                canMsg.append(hex(newMsg.ID))
                for i in range(8):
                    newMsg.DATA[i] = theMsg.DATA[i]
                    canMsg.append(''.join(hex(theMsg.DATA[i])).replace("0x", '').zfill(2))
                newMsg.MSGTYPE = theMsg.MSGTYPE
                print(canMsg)

                return theMsg
        except:
            # An error occurred, get a text describing the error and show it#
            resultERR = self.m_objPCANBasic.GetErrorText(result[0])
            print(resultERR[1])
            # return
            # self.HandleReadError(result[0])  # Possible errors handling function, HandleError(function_result)

    # 设定报文滤波
    def CANMsgFilter(self):
        #  The message filter is closed first to ensure the reception of the new range of IDs.
        #
        result = self.m_objPCANBasic.SetValue(PCAN_USBBUS1, PCAN_MESSAGE_FILTER, PCAN_FILTER_CLOSE)
        if result != PCAN_ERROR_OK:
            # An error occurred, get a text describing the error and show it
            #
            result = self.m_objPCANBasic.GetErrorText(result)
            print(result[1])
        else:
            # The message filter is configured to receive the IDs 2,3,4 and 5 on the PCAN-USB, Channel 1
            #
            result = self.m_objPCANBasic.FilterMessages(PCAN_USBBUS1, 0x7d0, 0x7d8, PCAN_MODE_STANDARD)
            if result != PCAN_ERROR_OK:
                # An error occurred, get a text describing the error and show it
                #
                result = self.m_objPCANBasic.GetErrorText(result)
                print(result[1])
            else:
                print("Filter successfully configured for IDs from 7D0 to 7D8.")

    def ResetBuffer(self):
        # The PCI Channel is released
        #
        result = self.m_objPCANBasic.Reset(PCAN_PCIBUS1)
        if result != PCAN_ERROR_OK:
            # An error occurred, get a text describing the error and show it
            #
            result = self.m_objPCANBasic.GetErrorText(result)
            print(result[1])
        else:
            print("PCAN-PCI (Ch-1) was reset")

    #---------------------------------------------------------------------------------------#
    def ReadDid(self, DID):
        if self.isCh1Open == True:
            if self.isCh1HasMes:
                if self.m_CanRead == False:
                    # DID 打印十六进制数
                    # re = int(DID, 16)
                    print("开始读取DID:", hex(DID))
                    if not self.conn.is_open():
                        self.conn.open()  # 打开连接
                    try:
                        self.udsclient.change_session(1)
                        resp = self.udsclient.read_data_by_identifier([DID])
                        UDS_str = resp.service_data.values[DID]
                        print('UDS发送请求成功')
                        self.conn.close()
                        # 将整数转换为十六进制字符串
                        if isinstance(UDS_str, int):
                            UDS_str_hex = hex(UDS_str)
                        else:
                            UDS_str_hex = str(UDS_str)  # 如果不是整数，保持原样
                        self.tb_message.append(f"读取DID的{hex(DID)}如下：")
                        self.tb_message.ensureCursorVisible()
                        self.tb_message.append(UDS_str_hex)
                        self.tb_message.ensureCursorVisible()
                        self.tb_message.moveCursor(self.tb_message.textCursor().End)
                    except Exception as e:
                        print('UDS发送请求失败')
                        qw.QMessageBox.information(self, '信息', f'DID读取失败:{str(e)}')
                else:
                    self.tb_message.append("提示：先打开Pcan链接！")
                    self.tb_message.ensureCursorVisible()
                    self.tb_message.moveCursor(self.tb_message.textCursor().End)
            else:
                self.tb_message.append("提示：CAN网络上没有报文！")
                self.tb_message.ensureCursorVisible()
                self.tb_message.moveCursor(self.tb_message.textCursor().End)
        else:
            self.tb_message.append("提示：通道未打开，请先打开通道！")
            self.tb_message.ensureCursorVisible()
            self.tb_message.moveCursor(self.tb_message.textCursor().End)



    # ------------------------------------------------------------------------------------- #
    # 定时函数
    def myTimer3E(self):
        timer = QTimer(self)
        timer.timeout.connect(self.service3E)
        timer.start(3000)

    #  定时发送3E服务
    def service3E(self):
        i = 0
        if self.is_extendMode:
            while (i < 5):  # 5次发送不成功则退出
                uds3E = self.CanMessage("uds3E")
                ret = self.WriteFrame(uds3E)
                if ret == PCAN_ERROR_OK:
                    break
                else:
                    i += 1
                    continue
            if i >= 5:
                print("发送失败！")
                return
        else:
            print("不发送3E服务")


    def list_of_groups(self, init_list, childern_list_len):
        list_of_groups = zip(*(iter(init_list),) * childern_list_len)
        end_list = [list(i) for i in list_of_groups]
        count = len(init_list) % childern_list_len
        end_list.append(init_list[-count:]) if count != 0 else end_list
        return end_list

    #报文接收函数
    def isotp_rcv(self):
        # We execute the "Read" function of the PCANBasic
        result = self.m_objPCANBasic.Read(self.m_PcanHandle)
        if result[0] == PCAN_ERROR_OK:
            # We show the received message
            RevMsg = TPCANMsg()
            RevMsg.ID = result[1].ID
            RevMsg.DLC = result[1].LEN
            for i in range(8 if (result[1].LEN > 8) else result[1].LEN):
                RevMsg.DATA[i] = result[1].DATA[i]
            RevMsg.MSGTYPE = result[1].MSGTYPE
        else:
            RevMsg = None
        return RevMsg

    #报文发送函数
    def isotp_send(self, isotp_msg):
        # isotp_msg.data.extend(bytearray([0xCC] * (8-len(isotp_msg.data))))
        CANMsg = TPCANMsg()
        CANMsg.ID = isotp_msg.arbitration_id
        CANMsg.LEN = isotp_msg.dlc
        CANMsg.MSGTYPE = PCAN_MESSAGE_STANDARD
        # If a remote frame will be sent, the data bytes are not important.
        if self.m_RemoteCHB.get():
            CANMsg.MSGTYPE |= PCAN_MESSAGE_RTR.value
        else:
            # We get so much data as the Len of the message
            for i in range(len(isotp_msg.data)):
                CANMsg.DATA[i] = isotp_msg.data[i]
        # The message is sent to the configured hardware
        ret = self.m_objPCANBasic.Write(self.m_PcanHandle, CANMsg)
        if ret != PCAN_ERROR_OK:
            print("发送失败")
        return

    #安全算法
    def hash_sha256(self, data):
        if isinstance(data, str):  # 如果输入的是字符串
            s = hashlib.sha256()  # Get the hash algorithm.
            s.update(data.encode('utf-8'))  # Hash the data.
            hashcode = s.hexdigest()  # Get he hash value.
        elif isinstance(data, bytes):  # 如果输入的是二进制数
            s = hashlib.sha256()  # Get the hash algorithm.
            s.update(data)  # Hash the data.
            hashcode = s.hexdigest()  # Get he hash value.
        else:
            print("Input data is not hashable.")
        return (hashcode)

    # Seed计算方法
    def SecAlgo(self, level, seed):
        print("SecAlgo")
        print("level=", level)
        bSeed = seed
        Cal = []
        Key = [0, 0, 0, 0]
        if level == 0x01:
            print("level01")
            for i in range(4):
                Cal.append(bSeed[i] ^ ecuXorArray[i])
            Key[0] = (((Cal[2] & 0xF0) << 4) | (Cal[3] & 0xF0)) & 0xFF
            Key[1] = (((Cal[3] & 0x2F) << 2) | (Cal[1] & 0x03)) & 0xFF
            Key[2] = (((Cal[1] & 0xFC) >> 2) | (Cal[0] & 0xC0)) & 0xFF
            Key[3] = (((Cal[0] & 0x0F) << 4) | (Cal[2] & 0x0F)) & 0xFF
            remainder = (Key[0] << 24) + (Key[1] << 16) + (Key[2] << 8) + Key[3]
            output_key = (remainder).to_bytes(4, 'big', signed=False)

        elif level == 0x61:
            print("level61")
            for i in range(4):
                Cal.append(bSeed[i] ^ ecuXorArray60[i])
            Key[0] = (((Cal[1] & 0x7F) << 2) | (Cal[2] & 0xF0)) & 0xFF
            Key[1] = (((Cal[0] & 0xEC) >> 2) | (Cal[1] & 0x7E)) & 0xFF
            Key[2] = (((Cal[3] & 0xF0) >> 4) | (Cal[0] & 0x2C)) & 0xFF
            Key[3] = (((Cal[2] & 0x0F) << 4) | (Cal[3] & 0x7d)) & 0xFF
            remainder = (Key[0] << 24) + (Key[1] << 16) + (Key[2] << 8) + Key[3]
            output_key = (remainder).to_bytes(4, 'big', signed=False)
            print("output_key=", output_key)

        elif level == 0x09:
            print("level09")
            for i in range(4):
                Cal.append(bSeed[i] ^ ecuXorArray[i])
            Key[0] = (((Cal[1] & 0x7F) << 2) | (Cal[2] & 0xF0)) & 0xFF
            Key[1] = (((Cal[0] & 0xEC) >> 2) | (Cal[1] & 0x7E)) & 0xFF
            Key[2] = (((Cal[3] & 0xF0) >> 4) | (Cal[0] & 0x2C)) & 0xFF
            Key[3] = (((Cal[2] & 0x0F) << 4) | (Cal[3] & 0x7d)) & 0xFF
            remainder = (Key[0] << 24) + (Key[1] << 16) + (Key[2] << 8) + Key[3]
            output_key = (remainder).to_bytes(4, 'big', signed=False)
        return output_key
    # ------------------------------------------------------------------------------------- #
    def start_receiving(self):
        try:

            self.start_receiving_flag = True
            self.pushButton_34.setEnabled(False)
            self.pushButton_36.setEnabled(True)
            if self.bus is None:
                # 初始化 CAN 总线
                if self.isCh1Open == True:
                    self.bus = self.canbus
                    pass
                else:
                    self.bus = openPCAN()
            self.receive_thread = CanReceiverThread(self.bus)
            self.receive_thread.message_received.connect(self.process_message)
            self.receive_thread.start()
        except Exception as e:
            QMessageBox.critical(self, "Error", f"Failed to start receiving: {e}")
            self.pushButton_34.setEnabled(True)
            self.pushButton_36.setEnabled(False)
            self.start_receiving_flag = False

    def stop_receiving(self):
        try:
            self.start_receiving_flag = False
            self.pushButton_34.setEnabled(True)
            self.pushButton_36.setEnabled(False)
            if self.receive_thread is not None:
                self.receive_thread.stop()
                self.receive_thread.wait()
        except Exception as e:
            QMessageBox.critical(self, "Error", f"Failed to stop receiving: {e}")

    def process_message(self, message):
        try:
            can_id = hex(message.arbitration_id)
            time_stamp = message.timestamp
            # 将时间戳转换为时分秒毫秒格式
            dt = datetime.fromtimestamp(time_stamp)
            formatted_time = dt.strftime("%H:%M:%S.%f")[:-3]  # 取前三位毫秒
            dlc = message.dlc
            data = ' '.join([f'{byte:02X}' for byte in message.data])

            # 如果 ID 已存在，覆盖原数据
            if can_id in self.data_dict:
                parent_item = self.data_dict[can_id]
                parent_item.setText(1, can_id)
                parent_item.setText(0, formatted_time)  # 使用格式化后的时间
                parent_item.setText(2, str(dlc))
                parent_item.setText(3, data)

                # 移除之前可能存在的解码数据行
                next_index = self.tree_widget.indexOfTopLevelItem(parent_item) + 1
                if next_index < self.tree_widget.topLevelItemCount():
                    next_item = self.tree_widget.topLevelItem(next_index)
                    if next_item.text(1) == f"{can_id}_decoded":
                        self.tree_widget.takeTopLevelItem(next_index)

            else:
                # 创建父项
                parent_item = QTreeWidgetItem(self.tree_widget)
                parent_item.setText(1, can_id)
                parent_item.setText(0, formatted_time)  # 使用格式化后的时间
                parent_item.setText(2, str(dlc))
                parent_item.setText(3, data)
                self.data_dict[can_id] = parent_item

            if self.db:
                try:
                    decoded_data = self.db.decode_message(message.arbitration_id, message.data)
                    decoded_data_str = ', '.join([f'{key}: {value}' for key, value in decoded_data.items()])
                    # 创建子项
                    if parent_item.childCount() > 0:
                        child_item = parent_item.child(0)
                        child_item.setText(4, decoded_data_str)
                    else:
                        child_item = QTreeWidgetItem(parent_item)
                        child_item.setText(4, decoded_data_str)
                        parent_item.addChild(child_item)
                    # 创建解码数据行
                    # decoded_item = QTreeWidgetItem(parent_item)
                    # decoded_item.setText(1, f"{can_id}_decoded")

                    # 创建 QTextEdit 控件来显示解码后的数据
                    text_edit = qw.QTextEdit()
                    text_edit.setPlainText(decoded_data_str)
                    text_edit.setReadOnly(True)
                    text_edit.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)

                    # 将 QTextEdit 控件插入到树状控件中
                    self.tree_widget.setItemWidget(child_item, 4, text_edit)

                    # 找到当前报文所在位置并插入解码数据行
                    index = self.tree_widget.indexOfTopLevelItem(parent_item)
                    self.tree_widget.insertTopLevelItem(index + 1, child_item)

                except KeyError:
                    # 如果 DBC 文件中没有对应的消息 ID，忽略解码错误
                    pass
                except Exception as decode_error:
                    QMessageBox.warning(self, "解码错误", f"解码 DBC 消息时出错: {decode_error}")

            self.sort_data()
        except Exception as e:
            QMessageBox.warning(self, "错误", str(e))

    #处理打开CAN总线的函数，处理普通的can通信内容
    # def process_message(self, message):
    #     try:
    #         can_id = hex(message.arbitration_id)
    #         time_stamp = message.timestamp
    #         # 将时间戳转换为时分秒毫秒格式
    #         dt = datetime.fromtimestamp(time_stamp)
    #         formatted_time = dt.strftime("%H:%M:%S.%f")[:-3]  # 取前三位毫秒
    #         dlc = message.dlc
    #         data = ' '.join([f'{byte:02X}' for byte in message.data])
    #
    #         # 如果 ID 已存在，覆盖原数据
    #         if can_id in self.data_dict:
    #             parent_item = self.data_dict[can_id]
    #             parent_item.setText(1, can_id)
    #             parent_item.setText(0, formatted_time)  # 使用格式化后的时间
    #             parent_item.setText(2, str(dlc))
    #             parent_item.setText(3, data)
    #
    #             if self.db:
    #                 try:
    #                     decoded_data = self.db.decode_message(message.arbitration_id, message.data)
    #                     decoded_data_str = ', '.join([f'{key}: {value}' for key, value in decoded_data.items()])
    #                     # 创建子项
    #                     if parent_item.childCount() > 0:
    #                         child_item = parent_item.child(0)
    #                         child_item.setText(4, decoded_data_str)
    #                     else:
    #                         child_item = QTreeWidgetItem(parent_item)
    #                         child_item.setText(4, decoded_data_str)
    #                         parent_item.addChild(child_item)
    #                 except KeyError:
    #                     # 如果 DBC 文件中没有对应的消息 ID，忽略解码错误
    #                     if parent_item.childCount() > 0:
    #                         parent_item.removeChild(parent_item.child(0))
    #                 except Exception as decode_error:
    #                     QMessageBox.warning(self, "解码错误", f"解码 DBC 消息时出错: {decode_error}")
    #                     if parent_item.childCount() > 0:
    #                         parent_item.removeChild(parent_item.child(0))
    #             else:
    #                 if parent_item.childCount() > 0:
    #                     parent_item.removeChild(parent_item.child(0))
    #         else:
    #             # 创建父项
    #             parent_item = QTreeWidgetItem(self.tree_widget)
    #             parent_item.setText(1, can_id)
    #             parent_item.setText(0, formatted_time)  # 使用格式化后的时间
    #             parent_item.setText(2, str(dlc))
    #             parent_item.setText(3, data)
    #             self.data_dict[can_id] = parent_item
    #
    #             if self.db:
    #                 try:
    #                     decoded_data = self.db.decode_message(message.arbitration_id, message.data)
    #                     decoded_data_str = ', '.join([f'{key}: {value}' for key, value in decoded_data.items()])
    #                     # 创建子项
    #                     child_item = QTreeWidgetItem(parent_item)
    #                     child_item.setText(4, decoded_data_str)
    #                     parent_item.addChild(child_item)
    #                 except KeyError:
    #                     # 如果 DBC 文件中没有对应的消息 ID，忽略解码错误
    #                     pass
    #                 except Exception as decode_error:
    #                     QMessageBox.warning(self, "解码错误", f"解码 DBC 消息时出错: {decode_error}")
    #             self.tree_widget.addTopLevelItem(parent_item)  # 添加到树状控件
    #
    #         self.sort_data()
    #     except Exception as e:
    #         QMessageBox.warning(self, "错误", str(e))

    def sort_data(self):
        try:

                self.tree_widget.sortItems(0, 0)  # 按 CAN ID 升序排序
        except Exception as e:
            QMessageBox.critical(self, "Error", f"Error sorting data: {e}")

    def add_dbc_file(self):
        try:
            # 暂停接收线程
            if self.receive_thread is not None and self.receive_thread.isRunning():
                self.receive_thread.stop()
                self.receive_thread.wait()
                self.pushButton_34.setEnabled(True)

            file_path, _ = qw.QFileDialog.getOpenFileName(self, "Select DBC File", "", "DBC Files (*.dbc)")
            if file_path:
                try:
                    self.db = cantools.database.load_file(file_path)
                except Exception as load_error:
                    QMessageBox.critical(self, "Error", f"Error loading DBC file: {load_error}")
                    return

            # # 恢复接收线程
            # if self.receive_thread is not None:
            #     self.tree_widget.clear()
            #     self.receive_thread = CanReceiverThread(self.bus)
            #     self.receive_thread.message_received.connect(self.process_message)
            #     self.receive_thread.start()

        except Exception as e:
            QMessageBox.critical(self, "Error", f"Error in add DBC file operation: {e}")

    def closeEvent(self, event):
        try:
            # 在程序关闭时关闭 CAN 总线
            if self.bus is not None:
                self.bus.shutdown()
            event.accept()
        except Exception as e:
            QMessageBox.critical(self, "Error", f"Error closing CAN bus: {e}")
            event.ignore()


# CAN接收线程
class CanReceiverThread(QThread):
    message_received = pyqtSignal(object)

    def __init__(self, bus):
        super().__init__()
        self.bus = bus
        self.running = False

    def run(self):
        self.running = True
        while self.running:
            try:
                message = self.bus.recv(timeout=1.0)
                if message is not None:
                    self.message_received.emit(message)
            except Exception as e:
                print(f"Error receiving CAN message: {e}")

    def stop(self):
        self.running = False



# ------------------------------------------------------------------------------------- #
if __name__ == '__main__':
    QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
    app = qw.QApplication(sys.argv)
    w = myMainWindow()
    w.show()
    sys.exit(app.exec_())
